package fox.framework.rpc.endpoint.netty.server;


import fox.framework.rpc.common.StringUtils;
import fox.framework.rpc.converter.RpcMessageConverter;
import fox.framework.rpc.exception.RpcRuntimeException;
import fox.framework.rpc.message.MappedRpcHeader;
import fox.framework.rpc.message.RpcHeader;
import fox.framework.rpc.server.dispatcher.router.DataBinder;
import fox.framework.rpc.server.message.request.RpcAttribute;
import fox.framework.rpc.server.message.request.RpcServerRequest;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @author cuichao
 * @Description: RpcServerRequestAPI
 * @Date: create in 2021/2/17 13:56
 */
public final class RpcDecodeServerRequest implements RpcServerRequest {

    private String protocol;

    private String path;

    private RpcHeader header = new MappedRpcHeader();

    private byte[] bodySource;

    private Object[] body;

    private volatile boolean isDecode = false;

    private RpcMessageConverter converter;

    private DataBinder[] binder;

    private Map<String, Object> attributes = new HashMap<>(16);

    /**
     * 设置协议
     *
     * @param protocol
     */
    void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    /**
     * 设置Path
     *
     * @param path
     */
    void setPath(String path) {
        this.path = path;
    }

    /**
     * 设置消息体
     *
     * @param bodySource
     */
    void setBodySource(byte[] bodySource) {
        this.bodySource = bodySource;
    }

    /**
     * 对消息体进行解码
     */
    private void decodeRequestBody() {
        if (isDecode) {
            return;
        }
        if(converter == null || binder == null){
         String msg = "the request decode miss some property: messageConverter or dataBinder";
         throw new RpcRuntimeException(msg);
        }
        //decode
        Object[] decode = converter.decode(bodySource, binder);
        this.body = decode;
        this.isDecode = true;

    }

    /**
     * 监听赋值属性时是否是解码属性
     *
     * @return
     */
    private boolean listenAttributeIsDecodeProperty(String name, Object value) {
        if (RpcAttribute.CONVERTER_NAME.equals(name) && assertInstance(value, RpcMessageConverter.class)) {
            converter = ((RpcMessageConverter) value);
            return true;
        } else if (RpcAttribute.DATA_BINDER.equals(name) && assertInstance(value, DataBinder[].class)) {
            binder = ((DataBinder[]) value);
            return true;
        }
        return false;
    }


    private boolean assertInstance(Object object, Class<?> cls) {
        if (cls.isInstance(object)) {
            return true;
        }
        return false;
    }


    @Override
    public String getProtocol() {
        return protocol;
    }

    @Override
    public String getPath() {
        return path;
    }

    @Override
    public void setHeader(String name, String value) {
        header.setHeader(name, value);
    }


    @Override
    public String getContentType() {
        return header.getHeader(RpcHeader.CONTENT_TYPE);
    }

    @Override
    public int getContentLength() {
        return new Integer(header.getHeader(RpcHeader.CONTENT_LENGTH));
    }

    @Override
    public String getHeader(String name) {
        return header.getHeader(name);
    }

    @Override
    public Collection<String> getHeaderNames() {
        return header.getHeaderNames();
    }


    @Override
    public void setAttribute(String name, Object value) {
        if (StringUtils.isEmpty(name) || value == null) {
            return;
        }
        if (!listenAttributeIsDecodeProperty(name, value)) {
            attributes.put(name, value);
        }
    }

    @Override
    public Object getAttribute(String name) {
        if (StringUtils.isEmpty(name)) {
            return null;
        }
        return attributes.getOrDefault(name, null);
    }

    @Override
    public Object[] getRequestBody() {
        if (isDecode) {
            return body;
        }
        decodeRequestBody();
        return body;
    }


}
